{
 "metadata": {
  "name": ""
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from __future__ import print_function\n",
      "import numba\n",
      "import numpy as np\n",
      "import math\n",
      "import llvm\n",
      "import ctypes\n",
      "print(\"numba version: %s \\nNumPy version: %s\\nllvm version: %s\" % (numba.__version__,np.__version__, llvm.__version__))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "numba version: 0.12.0-dirty \n",
        "NumPy version: 1.7.1\n",
        "llvm version: 0.12.0\n"
       ]
      }
     ],
     "prompt_number": 1
    },
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Numba and types"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Introduction"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "*Numba* translates *Python* code into fast executing native code. In order to generate fast native code, many dynamic features of *Python* need to be translated into static equivalents. This includes dynamic typing as well as polymorphism. The approach taken in *numba* is using *type inference* to generate *type information* for the code, so that it is possible to translate into native code. If all the values in a *numba* compiled function can be translated into native types, the resulting code will be competitive with that generated with a low level language. \n",
      "\n",
      "The objective of *type inference* is assigning a *type* to every single value in the function. The *type* of a value can either be:\n",
      "\n",
      "* *Implicit*, in the case of providing an object that will provide its *type*. This happens, for example, in literals.\n",
      "* *Explicit*, in the case of the programmer explicitly writing the *type* of a given value. This happens, for example, when a signature is given to *numba.jit*. That signature explicitly *types* the arguments.\n",
      "* *Inferred*, when the *type* is deduced from an operation and the types of the its operands. For example, inferring that the type of *a + b*, when *a* and *b* are of type *int* is going to be an *int*\n",
      "\n",
      "*Type inference* is the process by which all the *types* that are neither *implicit* nor *explicit* are deduced."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Type inference by example"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Let's take a very simple sample function to illustrate these concepts:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def sample_func(n):\n",
      "    tmp = n + 4;\n",
      "    return tmp + 3j;"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "When translating to native code it is needed to provide *type information* for every value involved in the sample function. This will include:\n",
      "\n",
      "* The *literals* **4** and **3j**. These two have an implicit type.\n",
      "* The argument **n**. In the function, as is, it is yet untyped.\n",
      "* Some intermediate values, like **tmp** and the **return value**. Their type is not known yet."
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Finding out the *types* of values"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "You can use the function *numba.typeof* to find out the *numba type* associated to a value. "
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print(numba.typeof.__doc__)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "    Get the type of a variable or value.\n",
        "\n",
        "    Used outside of Numba code, infers the type for the object.\n",
        "    \n"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Bear in mind that, when used from the *Python* interpreter, *numba.typeof* will return the *numba type* associated to the object passed as parameter. For example, let's try using it on the *literals* found in our sample function:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(4)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 4,
       "text": [
        "int32"
       ]
      }
     ],
     "prompt_number": 4
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(3j)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 5,
       "text": [
        "complex128"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Also note that the types of the results are *numba types*:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "type(numba.typeof(4))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 6,
       "text": [
        "numba.types.Integer"
       ]
      }
     ],
     "prompt_number": 6
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "As a note, when used inside *numba* compiled code, *numba.typeof* will return the type as inferred during *type inference*. This may be a more general *type* than the one which would be returned when evaluating using the *Python interpreter*."
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "*Type inference* in *numba.jit*"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Let's illustrate how type inference works with *numba.jit*. In order to illustrate this, we will use the *inspect_types* method of a compiled function and print information about the types being used while compiling.\n",
      "This will be the different native types when the function has been compiled successfully in *nopython* mode. If object mode has been used we will get plenty of *pyobject*s.\n",
      "\n",
      "Note that *inspect_types* is new to *numba 0.12*. Note also that the behavior of object mode has changed quite a bit as well in this release."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def jit_sample_1(n):\n",
      "    tmp = n + 4;\n",
      "    return tmp + 3j;"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 7
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.jit('c16(f8)', nopython=True)(jit_sample_1).inspect_types()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "jit_sample_1 (float64,) -> complex128\n",
        "--------------------------------------------------------------------------------\n",
        "# --- LINE 1 --- \n",
        "\n",
        "def jit_sample_1(n):\n",
        "\n",
        "    # --- LINE 2 --- \n",
        "    # label 0\n",
        "    #   $0.1 = const(<type 'int'>, 4)  :: int32\n",
        "    #   $0.2 = n + $0.1  :: float64\n",
        "    #   tmp = $0.2  :: float64\n",
        "\n",
        "    tmp = n + 4;\n",
        "\n",
        "    # --- LINE 3 --- \n",
        "    #   $0.3 = const(<type 'complex'>, 3j)  :: complex128\n",
        "    #   $0.4 = tmp + $0.3  :: complex128\n",
        "    #   return $0.4\n",
        "\n",
        "    return tmp + 3j;\n",
        "\n",
        "\n",
        "================================================================================\n"
       ]
      }
     ],
     "prompt_number": 8
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The source code of the original function should be shown with lines annotated with the values involved in that lines with its type annotated following a couple of double periods. The form will look like \"**value** = **expression** :: **type**\".\n",
      "\n",
      "In this case, the resulting function will get a float64 argument and return a complex128. The literal 4 will be of type int32 (\\$0.1), while the result of adding the argument (n) to that literal will be a float64 (\\$0.2). The variable in the source code named tmp will be just float64 (assigned from \\$0.2). In the same way we can trace the next expression and see how **tmp+3j** results in a complex128 value that will be used as return value. The values named _\\$0.*_ are intermmediate values for the expression, and do not have a named counterpart in the source code.\n",
      "\n",
      "\n",
      "\n",
      "If we were in *object* mode we would get something quite different. In order to illustrate, let's add the *forceobj* keyword to *numba.jit*. This will force *numba* to use object mode when compiling. Usually you don't want to use *forceobj* as *object* mode is slower than *nopython* mode:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.jit('c16(f8)', forceobj=True)(jit_sample_1).inspect_types()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "jit_sample_1 (pyobject,) -> pyobject\n",
        "--------------------------------------------------------------------------------\n",
        "# --- LINE 1 --- \n",
        "\n",
        "def jit_sample_1(n):\n",
        "\n",
        "    # --- LINE 2 --- \n",
        "    # label 0\n",
        "    #   $0.1 = const(<type 'int'>, 4)  :: pyobject\n",
        "    #   tmp = n + $0.1  :: pyobject\n",
        "\n",
        "    tmp = n + 4;\n",
        "\n",
        "    # --- LINE 3 --- \n",
        "    #   $0.3 = const(<type 'complex'>, 3j)  :: pyobject\n",
        "    #   $0.4 = tmp + $0.3  :: pyobject\n",
        "    #   return $0.4\n",
        "\n",
        "    return tmp + 3j;\n",
        "\n",
        "\n",
        "================================================================================\n"
       ]
      }
     ],
     "prompt_number": 9
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "As can be seen, everything is now a *pyobject*. That means that the operations will be executed by the Python runtime in the generated code."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Going back to the *nopython* mode, we can see how changing the input types will produced a different annotation for the code (and result in different code generation):\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.jit('c16(i1)')(jit_sample_1).inspect_types()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "jit_sample_1 (int8,) -> complex128\n",
        "--------------------------------------------------------------------------------\n",
        "# --- LINE 1 --- \n",
        "\n",
        "def jit_sample_1(n):\n",
        "\n",
        "    # --- LINE 2 --- \n",
        "    # label 0\n",
        "    #   $0.1 = const(<type 'int'>, 4)  :: int32\n",
        "    #   $0.2 = n + $0.1  :: int64\n",
        "    #   tmp = $0.2  :: int64\n",
        "\n",
        "    tmp = n + 4;\n",
        "\n",
        "    # --- LINE 3 --- \n",
        "    #   $0.3 = const(<type 'complex'>, 3j)  :: complex128\n",
        "    #   $0.4 = tmp + $0.3  :: complex128\n",
        "    #   return $0.4\n",
        "\n",
        "    return tmp + 3j;\n",
        "\n",
        "\n",
        "================================================================================\n"
       ]
      }
     ],
     "prompt_number": 10
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "In this case, the input is an int8, but tmp ends being and int64 as it is added to an int32. Note that integer overflow of int64 is not handled by *numba*. In case of overflow the int64 will wrap around in the same way that it would happen in C."
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Providing hints to the type inferrer"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "In most cases, the type inferrer will provide a type for your code. However, sometimes you may want a given intermediate value to use a specific type. This can be achieved by using the *locals* keyword in *numba.jit*. In *locals* a dictionary can be passed that maps the name of different local variables to a numba type. The compiler will assign that type to that variable.\n",
      "\n",
      "Let's make a version of out function where we force *tmp* to be a *float*:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.jit('c16(i1)', locals={'tmp': numba.float64})(jit_sample_1).inspect_types()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "jit_sample_1 (int8,) -> complex128\n",
        "--------------------------------------------------------------------------------\n",
        "# --- LINE 1 --- \n",
        "\n",
        "def jit_sample_1(n):\n",
        "\n",
        "    # --- LINE 2 --- \n",
        "    # label 0\n",
        "    #   $0.1 = const(<type 'int'>, 4)  :: int32\n",
        "    #   $0.2 = n + $0.1  :: int64\n",
        "    #   tmp = $0.2  :: float64\n",
        "\n",
        "    tmp = n + 4;\n",
        "\n",
        "    # --- LINE 3 --- \n",
        "    #   $0.3 = const(<type 'complex'>, 3j)  :: complex128\n",
        "    #   $0.4 = tmp + $0.3  :: complex128\n",
        "    #   return $0.4\n",
        "\n",
        "    return tmp + 3j;\n",
        "\n",
        "\n",
        "================================================================================\n"
       ]
      }
     ],
     "prompt_number": 11
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Note that as of numba 0.12, any type inference or type hints are ignored if object mode ends being generated, as everything gets treated as an object using the python runtime. This behavior may change in future versions."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.jit('c16(i1)', forceobj=True, locals={ 'tmp': numba.float64 })(jit_sample_1).inspect_types()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "jit_sample_1 (pyobject,) -> pyobject\n",
        "--------------------------------------------------------------------------------\n",
        "# --- LINE 1 --- \n",
        "\n",
        "def jit_sample_1(n):\n",
        "\n",
        "    # --- LINE 2 --- \n",
        "    # label 0\n",
        "    #   $0.1 = const(<type 'int'>, 4)  :: pyobject\n",
        "    #   tmp = n + $0.1  :: pyobject\n",
        "\n",
        "    tmp = n + 4;\n",
        "\n",
        "    # --- LINE 3 --- \n",
        "    #   $0.3 = const(<type 'complex'>, 3j)  :: pyobject\n",
        "    #   $0.4 = tmp + $0.3  :: pyobject\n",
        "    #   return $0.4\n",
        "\n",
        "    return tmp + 3j;\n",
        "\n",
        "\n",
        "================================================================================\n"
       ]
      }
     ],
     "prompt_number": 12
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Importance of type inference"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "It must be emphasized how important it is type inference in *numba*. A function where type inference is unable to provide a specific type for a value (that is, any type other than the generic *pyobject*). Any function that has a value fallback to *pyobject* will force the numba compiler to use the object mode. Object mode is way less efficient thant the *nopython*.\n",
      "\n",
      "It is possible to know if a *numba* compiled function has fallen back to object mode by calling *inspect_types* on it. If there are values typed as *pyobject* that means that the object mode was used to compile it."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Supported types in *numba*"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Numba supports many different types. It also supports some composite types as well as structures. Starting with numba 0.12 there is a namespace for types (numba.types). The numba namespace also imports these types."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "In this section you can find a set of basic types you can use in numba. Many of the types have a \"short name\" matching their equivalent NumPy dtype. The list is not exahustive."
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Integral types"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<table><tr><th>type</th><th>numba type</th><th>short name</th><th>python equivalent</th></tr>\n",
      "<tr><td>boolean</td><td>numba.types.bool__</td><td>b1</td><td>bool</td></tr>\n",
      "<tr><td>signed integer</td><td>numba.types.int__</td><td></td><td>int</td></tr>\n",
      "<tr><td>signed integer (8 bit)</td><td>numba.types.int8</td><td>i1</td><td></td></tr>\n",
      "<tr><td>signed integer (16 bit)</td><td>numba.types.int16</td><td>i2</td><td></td></tr>\n",
      "<tr><td>signed integer (32 bit)</td><td>numba.types.int32</td><td>i4</td><td></td></tr>\n",
      "<tr><td>signed integer (64 bit)</td><td>numba.types.int64</td><td>i8</td><td></td></tr>\n",
      "<tr><td>unsigned integer</td><td>numba.types.uint</td><td></td><td></td></tr>\n",
      "<tr><td>unsigned integer (16 bit)</td><td>numba.types.uint16</td><td>u2</td><td></td></tr>\n",
      "<tr><td>unsigned integer (32 bit)</td><td>numba.types.uint32</td><td>u4</td><td></td></tr>\n",
      "<tr><td>unsigned integer (64 bit)</td><td>numba.types.uint64</td><td>u8</td><td></td></tr>\n",
      "</table>"
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Floating point types"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<table><tr><th>type</th><th>numba type</th><th>short name</th><th>python equivalent</th></tr>\n",
      "<tr><td>single precision floating point (32 bit)</td><td>numba.float32</td><td>f4</td><td></td></tr>\n",
      "<tr><td>double precision floating point (64 bit)</td><td>numba.float64</td><td>f8</td><td>float</td></tr>\n",
      "<tr><td>single precision complex (2 x 32 bit)</td><td>numba.complex64</td><td>c8</td><td></td></tr>\n",
      "<tr><td>double precison complex (2 x 64 bit)</td><td>numba.complex128</td><td>c16</td><td>complex</td></tr>\n",
      "</table>"
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Array types"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Array types are supported. An array type is built from a base type, a number of dimensions and potentially a layout specification. Some examples follow:\n",
      "\n",
      "A one-dimensional array of float32"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.types.float32[:]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 13,
       "text": [
        "array(float32, 1d, A)"
       ]
      }
     ],
     "prompt_number": 13
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(np.zeros((12,2), dtype=np.float32)[:,0]) # slicing out the inner dimension to avoid defaulting to C array order in the result"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 14,
       "text": [
        "array(float32, 1d, A)"
       ]
      }
     ],
     "prompt_number": 14
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A two dimensional array of integers"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.types.int_[:,:]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 15,
       "text": [
        "array(uint32, 2d, A)"
       ]
      }
     ],
     "prompt_number": 15
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(np.zeros((12,2,2), dtype='i')[:,0]) # slicing out the inner dimension to avoid defaulting to C array order in the result"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 16,
       "text": [
        "array(int32, 2d, A)"
       ]
      }
     ],
     "prompt_number": 16
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A two dimensional array of type 'c8' (complex64) in C array order"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.types.c8[:,::1]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 17,
       "text": [
        "array(complex64, 2d, C)"
       ]
      }
     ],
     "prompt_number": 17
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(np.zeros((12,12), dtype='c8', order='C'))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 18,
       "text": [
        "array(complex64, 2d, C)"
       ]
      }
     ],
     "prompt_number": 18
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A two dimensional array of type uint16 in FORTRAN array order"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.types.uint16[::1,:]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 19,
       "text": [
        "array(uint16, 2d, F)"
       ]
      }
     ],
     "prompt_number": 19
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(np.zeros((12,12), dtype='u2', order='F'))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 20,
       "text": [
        "array(uint16, 2d, F)"
       ]
      }
     ],
     "prompt_number": 20
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Notice that the arity of the dimensions is not part of the types, only the number of dimensions. In that sense, an array with a shape (4,4) has the same numba type as another array with a shape (10, 12)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(np.zeros((4,4))) == numba.typeof(np.zeros((10,12)))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 21,
       "text": [
        "True"
       ]
      }
     ],
     "prompt_number": 21
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "Some extra types"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A type signature for a function (also known as a *function prototype*) that returns a float64, taking a two dimensional float64 array as first argument and a float64 argument"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.types.float64(numba.types.float64[:,:], numba.types.float64)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 22,
       "text": [
        "float64(array(float64, 2d, A), float64)"
       ]
      }
     ],
     "prompt_number": 22
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "As can be seen the signature is just a type specification. In many places that a *function signature* is expected a string can be used instead. That string is in fact evaluated inside the numba.types namespace in order to build the actual type. This allows specifying the types in a compact way (as there is no need to fully qualify the base types) without polluting the active namespace (as it would happen by adding a __from numba.types import *__.\n",
      "\n",
      "In _numba_ 0.12 this is performed by the *numba.sigutils.parse_signature* function. Note that this function is likely to change or move in next versions, as it is just an implementation detail, but it can be used to show how the string version matches the other one, while keeping the sync "
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.sigutils.parse_signature('float64(float64[:,:], float64)')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 23,
       "text": [
        "float64(array(float64, 2d, A), float64)"
       ]
      }
     ],
     "prompt_number": 23
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A generic Python object"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.types.pyobject"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 24,
       "text": [
        "pyobject"
       ]
      }
     ],
     "prompt_number": 24
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Notes about changes in this tutorial"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "In *numba* 0.12 there have been internal changes that have made material previously found in this tutorial obsolete.\n",
      "\n",
      "+ Some of the types previously supported in the *numba* type system have been dropped to be handled as *pyobjects*.\n",
      "\n",
      "+ The numba command line tool is no longer supported, but its functionality to get insights on how type inference works is now present in the form of the *inspect_types* method in the generated jitted function. This method is used in this tutorials to illustrate type inference.\n",
      "\n",
      "+ In 0.12 the object mode of *numba* has been greatly modified. Before it was using a mix of Python run-time and native code. In 0.12 object mode forces all values into *pyobjects*. As conversion to a string forces *numba* into object mode, the approach used in the previous version of this tutorial to print from inside the compiled function is no longer useful, as it will not print the staticly inferred types.\n",
      "\n",
      "A sample of the this last point follows:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def old_style_sample(n):\n",
      "    print('arg n: '+ str(numba.typeof(n)))\n",
      "    print('literal 4: ' + str(numba.typeof(4))) \n",
      "    tmp = n + 4;\n",
      "    print('tmp: '+ str(numba.typeof(tmp)))\n",
      "    print('literal 3j:' + str(numba.typeof(3j)))\n",
      "    return tmp + 3j;"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 25
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "old_style_sample_jit = numba.jit('void(i1)')(old_style_sample)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 26
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(old_style_sample(42))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "arg n: int32\n",
        "literal 4: int32\n",
        "tmp: int32\n",
        "literal 3j:complex128\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 27,
       "text": [
        "complex128"
       ]
      }
     ],
     "prompt_number": 27
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(old_style_sample_jit(42))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "arg n: int32\n",
        "literal 4: int32\n",
        "tmp: int32\n",
        "literal 3j:complex128\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 28,
       "text": [
        "complex128"
       ]
      }
     ],
     "prompt_number": 28
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "As can be seen, in both cases, Python and numba.jit, the results are the same. This is because *numba.typeof* is being evaluated by using the Python run-time.\n",
      "\n",
      "If we use the inspect_types method on the jitted version, we will see that everything is in fact a *pyobject*"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "old_style_sample_jit.inspect_types()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "old_style_sample (pyobject,) -> pyobject\n",
        "--------------------------------------------------------------------------------\n",
        "# --- LINE 1 --- \n",
        "\n",
        "def old_style_sample(n):\n",
        "\n",
        "    # --- LINE 2 --- \n",
        "    # label 0\n",
        "    #   $0.1 = global(print: <built-in function print>)  :: pyobject\n",
        "    #   $0.2 = const(<type 'str'>, arg n: )  :: pyobject\n",
        "    #   $0.3 = global(str: <type 'str'>)  :: pyobject\n",
        "    #   $0.4 = global(numba: <module 'numba' from '/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/__init__.pyc'>)  :: pyobject\n",
        "    #   $0.5 = getattr(attr=typeof, value=$0.4)  :: pyobject\n",
        "    #   $0.6 = call $0.5(n, )  :: pyobject\n",
        "    #   $0.7 = call $0.3($0.6, )  :: pyobject\n",
        "    #   $0.8 = $0.2 + $0.7  :: pyobject\n",
        "    #   $0.9 = call $0.1($0.8, )  :: pyobject\n",
        "\n",
        "    print('arg n: '+ str(numba.typeof(n)))\n",
        "\n",
        "    # --- LINE 3 --- \n",
        "    #   $0.10 = global(print: <built-in function print>)  :: pyobject\n",
        "    #   $0.11 = const(<type 'str'>, literal 4: )  :: pyobject\n",
        "    #   $0.12 = global(str: <type 'str'>)  :: pyobject\n",
        "    #   $0.13 = global(numba: <module 'numba' from '/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/__init__.pyc'>)  :: pyobject\n",
        "    #   $0.14 = getattr(attr=typeof, value=$0.13)  :: pyobject\n",
        "    #   $0.15 = const(<type 'int'>, 4)  :: pyobject\n",
        "    #   $0.16 = call $0.14($0.15, )  :: pyobject\n",
        "    #   $0.17 = call $0.12($0.16, )  :: pyobject\n",
        "    #   $0.18 = $0.11 + $0.17  :: pyobject\n",
        "    #   $0.19 = call $0.10($0.18, )  :: pyobject\n",
        "\n",
        "    print('literal 4: ' + str(numba.typeof(4)))\n",
        "\n",
        "    # --- LINE 4 --- \n",
        "    #   $0.20 = const(<type 'int'>, 4)  :: pyobject\n",
        "    #   tmp = n + $0.20  :: pyobject\n",
        "\n",
        "    tmp = n + 4;\n",
        "\n",
        "    # --- LINE 5 --- \n",
        "    #   $0.22 = global(print: <built-in function print>)  :: pyobject\n",
        "    #   $0.23 = const(<type 'str'>, tmp: )  :: pyobject\n",
        "    #   $0.24 = global(str: <type 'str'>)  :: pyobject\n",
        "    #   $0.25 = global(numba: <module 'numba' from '/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/__init__.pyc'>)  :: pyobject\n",
        "    #   $0.26 = getattr(attr=typeof, value=$0.25)  :: pyobject\n",
        "    #   $0.27 = call $0.26(tmp, )  :: pyobject\n",
        "    #   $0.28 = call $0.24($0.27, )  :: pyobject\n",
        "    #   $0.29 = $0.23 + $0.28  :: pyobject\n",
        "    #   $0.30 = call $0.22($0.29, )  :: pyobject\n",
        "\n",
        "    print('tmp: '+ str(numba.typeof(tmp)))\n",
        "\n",
        "    # --- LINE 6 --- \n",
        "    #   $0.31 = global(print: <built-in function print>)  :: pyobject\n",
        "    #   $0.32 = const(<type 'str'>, literal 3j:)  :: pyobject\n",
        "    #   $0.33 = global(str: <type 'str'>)  :: pyobject\n",
        "    #   $0.34 = global(numba: <module 'numba' from '/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/__init__.pyc'>)  :: pyobject\n",
        "    #   $0.35 = getattr(attr=typeof, value=$0.34)  :: pyobject\n",
        "    #   $0.36 = const(<type 'complex'>, 3j)  :: pyobject\n",
        "    #   $0.37 = call $0.35($0.36, )  :: pyobject\n",
        "    #   $0.38 = call $0.33($0.37, )  :: pyobject\n",
        "    #   $0.39 = $0.32 + $0.38  :: pyobject\n",
        "    #   $0.40 = call $0.31($0.39, )  :: pyobject\n",
        "\n",
        "    print('literal 3j:' + str(numba.typeof(3j)))\n",
        "\n",
        "    # --- LINE 7 --- \n",
        "    #   $0.41 = const(<type 'complex'>, 3j)  :: pyobject\n",
        "    #   $0.42 = tmp + $0.41  :: pyobject\n",
        "    #   return $0.42\n",
        "\n",
        "    return tmp + 3j;\n",
        "\n",
        "\n",
        "================================================================================\n"
       ]
      }
     ],
     "prompt_number": 29
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Even more illustrating would be if *locals* was used to type an intermediate value:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "old_style_sample_jit_2 = numba.jit('void(i1)', locals={'tmp': numba.float32})(old_style_sample)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 30
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "numba.typeof(old_style_sample_jit_2(42))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "arg n: int32\n",
        "literal 4: int32\n",
        "tmp: int32\n",
        "literal 3j:complex128\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 31,
       "text": [
        "complex128"
       ]
      }
     ],
     "prompt_number": 31
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The result seems to imply that *tmp* appears as an int32, but in fact is a *pyobject* and the whole function is being evaluated using the python run-time. So it is actually showing evaluating *typeof* at the runtime on the run-time value of tmp, which happens to be a Python *int*, translated into an int32 by *numba.typeof*. This can also be seen in the dump caused by the call to inspect_types."
     ]
    }
   ],
   "metadata": {}
  }
 ]
}
